package com.bf.hotpoint.service.impl;

import java.io.File;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.UUID;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.commons.lang.NullArgumentException;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.geo.Point;
import org.springframework.stereotype.Service;

import com.bf.hotpoint.applepushnotification.PushNotification;
import com.bf.hotpoint.common.LogValues;
import com.bf.hotpoint.common.SystemConfigValues;
import com.bf.hotpoint.domain.Message;
import com.bf.hotpoint.domain.Reply;
import com.bf.hotpoint.enums.ResultCodeEnum;
import com.bf.hotpoint.exception.MessageNotExistException;
import com.bf.hotpoint.repository.mongo.MessageMongoRepository;
import com.bf.hotpoint.service.MessageService;

@Service
public class MessageServiceImpl implements MessageService{

	static Logger log = Logger.getLogger(MessageServiceImpl.class.getName());
	
	@Autowired
	private MessageMongoRepository messageMongoRepository;
	
	@Autowired
	private PushNotification pushNotification;
	
	private Date getAfterTime(int seconds)
	{
		Calendar c=new GregorianCalendar();
		c.add(Calendar.SECOND, seconds);
		return c.getTime();
	}
	
	public ResultCodeEnum addMessage(String uuid,String deviceToken, String content, String title, List<String> images, Point location,int liveSeconds,String subject,String nickName,Boolean isMale,Boolean hasUserHead) {
		try {

			if(uuid == null || uuid.isEmpty())
			{
				throw new NullArgumentException("uuid of message is null");
			}
			if(content == null || content.isEmpty())
			{
				throw new NullArgumentException("content of message is null");
			}
			if(title.length() > 10)
			{
				throw new IllegalArgumentException("title length is over max length");
			}
			if(location == null)
			{
				throw new NullArgumentException("location of message is null");
			}
			if(content.length() > 120)
			{
				throw new IllegalArgumentException("content of message is over max length");
			}

			Message message = new Message();
			
			if(liveSeconds > 1)
			{
				message.setAvailableTime(this.getAfterTime(liveSeconds));
			}
			else
			{
				message.setAvailableTime(this.getAfterTime(SystemConfigValues.availableHoursOfMessage*60*60));
			}
			
			if(images == null || images.size() < 1)
			{
				message.setHasImage(false);
			}
			else
			{
				message.setHasImage(true);
			}
			message.setNickName(nickName);
			message.setAvailable(true);
			message.setContent(content);
			message.setHasUserHead(hasUserHead);
			message.setUuid(uuid);
			message.setDeviceToken(deviceToken);
			message.setImages(images);
			Set<String> keywords = this.getKeyWords(content);
			message.setKeyWords(keywords);
			message.setSex(isMale);
			message.setLocation(location);
			message.setNumberOfDespise(0);
			message.setNumberOfPraise(0);
			message.setPublishTime(new Date());
			message.setReplies(new ArrayList<Reply>());
			message.setReportedUsers(new HashSet<String>());
			message.setTitle(title);
		
			messageMongoRepository.addMessage(message);
			log.info("add message successfully "+ message);
			System.out.println("add message successfully "+ message);
			if(liveSeconds == 10*60)
			{
				LogValues.tenMinsSum ++;
			}
			else if(liveSeconds == 30*60)
			{
				LogValues.thirtyMinsSum ++;
			}
			else if(liveSeconds == 60*60)
			{
				LogValues.sixtyMinsSum ++;
			}
		} catch (NullArgumentException e) {
			log.error("argument of message is empty", e);
			return ResultCodeEnum.PARAMETER_IS_NULL;
		}	
		catch (IllegalArgumentException e) {
			log.error("argument of message error", e);
			return ResultCodeEnum.PARAMETER_IS_WRONG;
		}	
		catch (Exception e) {
			log.error("add message error", e);
			return ResultCodeEnum.CREATE_MESSAGE_FAILURE;
		}	
		return ResultCodeEnum.SUCCESS;
	}
	
	public Set<String> getKeyWords(String content)
	{
		Set<String> resultSet = new HashSet<String>();
		Pattern p = Pattern.compile("#[^#]+#");  
        Matcher m = p.matcher(content);// 开始编译  
        while (m.find()) {  
            int gc = m.groupCount();  
            String group = m.group(1);  
            if (!"".equals(group)) {  
                System.out.println(gc + group);  
                resultSet.add(group);  
            }  
        } 
		return resultSet;
	}

	public Message getAvailableMessageById(String messageId)
	{
		Message message = messageMongoRepository.getMessage(messageId);
		if(message != null || message.isAvailable())
		{
			return message;
		}
		return null;
	}
	
	public String getUuidByMessageId(String messageId) throws Exception
	{
		Message message = this.getAvailableMessageById(messageId);
		if(message == null || !message.isAvailable())
		{
			throw new MessageNotExistException(messageId + "not exsit");
		}
		return message.getUuid();
	}
	
	public void reportMessageByMessageId(String messageId,String reportUuid)
	{
		try {
			Message message = this.getAvailableMessageById(messageId);
			/**
			Set<String> reportedUserIds = message.getReportedUsers();
			reportedUserIds.add(reportUuid);
			message.setReportedUsers(reportedUserIds);
			if(message.getReportedUsers().size() >= SystemConfigValues.INSTANCE.maxReportedOfMessage)
			
			
				message.setAvailable(false);
			}
			*/
			message.setReported(true);
			messageMongoRepository.updateMessage(message);
		} catch (Exception e) {
			log.error("report message error", e);
			System.out.println(e);
		}
	}
	
	public List<Message> getMessages(boolean newOrHot,int lastIndex,String subject,double locationx,double locationy,Long startSearchTime) throws Exception 
	{
		try {
			List<Message> messages = new ArrayList<Message>();
			
			Date startSearchTimeDate = null;
			if(startSearchTime != null)
			{
				startSearchTimeDate = new Date(startSearchTime);
			}
			
			if(subject != null && !subject.isEmpty())
			{
				if(startSearchTimeDate == null)
					messages = messageMongoRepository.getMessages(lastIndex,SystemConfigValues.pageSize,subject);
				else
					messages = messageMongoRepository.getMessages(lastIndex,SystemConfigValues.pageSize,subject,startSearchTimeDate);
			}
			else
			{
				List<Message> allMessages =null;
				if(startSearchTimeDate == null)
					allMessages = messageMongoRepository.getMessages(lastIndex, SystemConfigValues.pageSize, new Point(locationx,locationy),SystemConfigValues.distanceOfDegree/111.12);
				else
					allMessages = messageMongoRepository.getMessages(lastIndex, SystemConfigValues.pageSize, new Point(locationx,locationy),SystemConfigValues.distanceOfDegree/111.12,startSearchTimeDate);
				//因为mongo的bug，所以用代码进行分页
				int firstIndex = lastIndex + 1;
				if(lastIndex < 0)
				{
					firstIndex = 0;
				}
				for(int i = firstIndex;i < firstIndex+SystemConfigValues.pageSize;i++)
				{
					if(i >= allMessages.size())
					{
						break;
					}
					messages.add(allMessages.get(i));
				}
				
			}
			return messages;	
		} catch (Exception e) {
			log.error(e);
		}
		return null;
	}
	
	public List<Message> getMessagesByIds(List<String> messageIds)
	{
		List<Message> messages = messageMongoRepository.getMessages(messageIds);
		if(messages == null)
		{
			messages = new ArrayList<Message>();
		}
		return messages;
	}
	
	public ResultCodeEnum postReply(String uuid,String deviceToken,String content,String messageid,String nickName,String toNickName,String toUuid,boolean sex,String toDeviceToken)
	{
		try {

			if(uuid == null || uuid.isEmpty())
			{
				throw new NullArgumentException("uuid of message is null");
			}
			if(content == null || content.isEmpty())
			{
				throw new NullArgumentException("content of message is null");
			}
			if(content.length() > 120)
			{
				throw new IllegalArgumentException("content of message is over max length");
			}

			Reply reply = new Reply();
			reply.setUuid(uuid);
			reply.setDeviceToken(deviceToken);
			reply.setNickName(nickName);
			reply.setToNickName(toNickName);
			reply.setToUuid(toUuid);
			reply.setContent(content);
			reply.setPublishTime(new Date());
			reply.setAvailable(true);
			reply.setSex(sex);
			reply.setReplyId(UUID.randomUUID().toString());

			boolean isSuccess = messageMongoRepository.addReplyToMessageByMessageId(messageid, reply);
			if(isSuccess){
				
				String pushContent = "";
				if(toNickName == null)
				{
					pushContent = nickName + " 评论了你";
					
				}
				else
				{
					pushContent = nickName + ":" + content.substring(0, 5);
					if(content.length() > 6)
						pushContent = pushContent + "...";
				}
				
				LogValues.commentSum ++;
				if(!uuid.equals(toUuid)){
					pushNotification.pushNotification(toDeviceToken, pushContent,messageid);
				}
				return ResultCodeEnum.SUCCESS;
			}
			else{
				return ResultCodeEnum.CREATE_REPLY_FAILURE;
			}
		} catch (NullArgumentException e) {
			log.error("argument of reply is empty", e);
			return ResultCodeEnum.PARAMETER_IS_NULL;
		}
		catch (IllegalArgumentException e) {
			log.error("argument of reply error", e);
			return ResultCodeEnum.PARAMETER_IS_WRONG;
		}
		catch (Exception e) {
			log.error("add reply error", e);
			return ResultCodeEnum.CREATE_REPLY_FAILURE;
		}
	}
	public void praiseOrDespise(boolean isPraiseOrDespise,String uuid,String messageId)
	{
		Message message = this.getAvailableMessageById(messageId);
		if(message == null)
		{
			return;
		}
		if(isPraiseOrDespise)
			message.setNumberOfPraise(message.getNumberOfPraise()+1);
		else
			message.setNumberOfDespise(message.getNumberOfDespise()+1);
		
		messageMongoRepository.updateMessage(message);
	}
	
	public void deleteExpireMessages()
	{
		String rootPath = System.getProperty("catalina.home");
		File dir = new File(rootPath + File.separator + "messageImages");
	    File[] files = dir.listFiles();
	    Date now = new Date();
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(now);
		calendar.add(Calendar.HOUR_OF_DAY, -1);
		Date oneHourAgo = calendar.getTime();
		for(int i = 0; i < files.length ; i++)
		{
			try {
				File file = files[i];
				if(file == null)
				{
					continue;
				}
				long insertLong = file.lastModified();
				Date insterTime = new Date(insertLong);
				if(oneHourAgo.after(insterTime))
				{
					file.delete();
				}	
			} catch (Exception e) {
				// TODO: handle exception
			}
		}
	}
}
